Github.currentUser   A
last analyzed

Complexity

Conditions 5

Size

Total Lines 18
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 15
dl 0
loc 18
rs 9.1832
c 0
b 0
f 0
1
import { APP_VERSION } from '@/lib/consts';
2
import { RepositoryInfo } from '@/types/RepositoryInfo';
3
import { Octokit } from '@octokit/core/dist-node/index';
4
import { throttling } from '@octokit/plugin-throttling';
5
6
let AppOctokitDefaults: typeof Octokit;
7
8
export function initOctokit(token: string) {
9
    AppOctokitDefaults = Octokit.defaults({
10
        auth: token,
11
        log: console,
12
        userAgent: `codeboost/v${APP_VERSION}`,
13
    });
14
15
    AppOctokitDefaults.plugin(throttling);
16
}
17
18
export function createOctokit(): Octokit {
19
    const result = new AppOctokitDefaults({
20
        throttle: {
21
            onRateLimit: (retryAfter, options, octokit, retryCount) => {
22
                result.log.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
23
24
                // retries twice
25
                if (retryCount < 2) {
26
                    result.log.info(`Retrying after ${retryAfter} seconds!`);
27
                    return true;
28
                }
29
            },
30
            onSecondaryRateLimit: (retryAfter, options, octokit) => {
31
                // does not retry, only logs a warning
32
                result.log.warn(`SecondaryRateLimit detected for request ${options.method} ${options.url}`);
33
            },
34
        },
35
    });
36
37
    return result;
38
}
39
40
/**
41
 * A class for interacting with the Github API
42
 */
43
export class Github {
44
    protected static cache = { currentUser: null as { login: string } | null };
45
46
    static async setCache(cache: any) {
47
        Github.cache = cache;
48
    }
49
50
    static async currentUser(octokit: Octokit | null = null) {
51
        octokit = octokit ?? createOctokit();
52
53
        if (Github.cache.currentUser) {
54
            return Github.cache.currentUser;
55
        }
56
57
        // get currently authenticated user
58
        const user = await octokit.request('GET /user');
59
60
        if (user.status !== 200) {
61
            throw new Error('Failed to get currently authenticated user');
62
        }
63
64
        Github.cache.currentUser = { login: user.data.login };
65
66
        return user.data;
67
    }
68
69
    /**
70
     * Attempts to fork a repository into the currently authenticated user's account.
71
     * Throws an error if the fork already exists.
72
     * @param {Repository} repository
73
     * @param {Octokit|null} octokit
74
     */
75
    static async forkRepository(repository: RepositoryInfo, octokit: Octokit | null = null) {
76
        octokit = octokit ?? createOctokit();
77
78
        const currentUserLogin = (await Github.currentUser(octokit)).login;
79
80
        if (currentUserLogin === repository.owner) {
81
            throw new Error(`Cannot fork repository ${repository.owner}/${repository.name} into itself`);
82
        }
83
84
        const result = await octokit.request(`POST /repos/${repository.owner}/${repository.name}/forks`, {
85
            owner: currentUserLogin,
86
            repo: this.name,
87
            default_branch_only: true,
88
        });
89
90
        if (result.status !== 202) {
91
            throw new Error(`Failed to create fork of ${repository.owner}/${repository.name}`);
92
        }
93
94
        return result.data;
95
    }
96
97
    static async getRepository(repository: RepositoryInfo, octokit: Octokit | null = null) {
98
        octokit = octokit ?? createOctokit();
99
100
        const result = await octokit.request(`GET /repos/${repository.owner}/${repository.name}`);
101
102
        if (result.status !== 200) {
103
            throw new Error(`Failed to get repository ${repository.owner}/${repository.name}`);
104
        }
105
106
        return result.data;
107
    }
108
109
    // create a pull request
110
    static async createPullRequest(
111
        repository: RepositoryInfo,
112
        branchName: string,
113
        defaultBranchName: string,
114
        title: string,
115
        body: string,
116
        octokit: Octokit | null = null,
117
        isForkPr = true,
118
    ) {
119
        octokit = octokit ?? createOctokit();
120
121
        const currentUsername = (await Github.currentUser(octokit)).login;
122
123
        const result = await octokit.request(`POST /repos/${repository.owner}/${repository.name}/pulls`, {
124
            owner: currentUsername,
125
            repo: repository.name,
126
            title,
127
            body,
128
            head: `${isForkPr ? currentUsername + ':' : ''}${branchName}`,
129
            base: defaultBranchName,
130
        });
131
132
        if (result.status !== 201) {
133
            throw new Error(`Failed to create pull request for ${currentUsername}/${repository.name}`);
134
        }
135
136
        return result.data;
137
    }
138
139
    static async mergePullRequest(repository: RepositoryInfo, pullRequestNumber: number, octokit: Octokit | null = null) {
140
        octokit = octokit ?? createOctokit();
141
142
        const result = await octokit.request(`PUT /repos/${repository.owner}/${repository.name}/pulls/${pullRequestNumber}/merge`, {
143
            owner: repository.owner,
144
            repo: repository.name,
145
            pull_number: pullRequestNumber,
146
            merge_method: 'merge',
147
        });
148
149
        if (result.status !== 200) {
150
            throw new Error(`Failed to merge pull request for ${repository.owner}/${repository.name}`);
151
        }
152
153
        return result.data;
154
    }
155
}
156